package com.sunyy.codegenerator.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.core.util.ZipUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.sunyy.codegenerator.common.MyException;
import com.sunyy.codegenerator.config.freemarker.MyByteArrayTemplateLoader;
import com.sunyy.codegenerator.dto.codeGenerator.GenerateDto;
import com.sunyy.codegenerator.dto.codeGenerator.YinhaiProjectGenerateDto;
import com.sunyy.codegenerator.entity.TemplateFileInfo;
import com.sunyy.codegenerator.entity.TemplateGroup;
import com.sunyy.codegenerator.service.CodeGeneratorService;
import com.sunyy.codegenerator.service.TemplateFileInfoService;
import com.sunyy.codegenerator.service.TemplateGroupService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author sunyy
 * @date 2025/7/10
 */
@Slf4j
@Service
@Transactional
public class CodeGeneratorServiceImpl implements CodeGeneratorService {

    @Resource
    private TemplateFileInfoService templateFileInfoService;

    @Resource
    private TemplateGroupService templateGroupService;

    @Resource(name = "freeMarkerTemplateConf")
    private Configuration templateConf;

    @Value("${free-marker.output-path}")
    private String savePathStr;

    @Override
    public void yinhaiProjectGenerate(YinhaiProjectGenerateDto dto, HttpServletResponse response) {
//        String templateName = dto.getTemplateName();
//        if (!StringUtils.hasText(templateName)) {
//            throw new RuntimeException("模板名称【templateName】不能为空!!");
//        }
//        String templateRootPathStr = freeMarkerConfig.getTemplatePath();
//        String javaFileTemplateName = Character.toUpperCase(templateName.charAt(0)) + templateName.substring(1);
//        Path templateRootPath = Paths.get(templateRootPathStr);
//        if (!StringUtils.hasText(dto.getJavaModelName())) {
//            dto.setJavaModelName(dto.getModelName());
//        }
//        String javaFileModelName = dto.getJavaModelName();
//        String javaName = Character.toUpperCase(javaFileModelName.charAt(0)) + javaFileModelName.substring(1);
//        dto.setJavaModelName(javaName);
//        // 获取模板位置
//        Path modelRootPath = templateRootPath.resolve(templateName);
//        // 获取保存位置
//        Path savePath = Paths.get(savePathStr, dto.getModelName());
//        File file = savePath.toFile();
//        if (!file.exists()) {
//            file.mkdirs();
//        }
//        // 获取模板配置
//        try {
//            Files.walkFileTree(modelRootPath, new SimpleFileVisitor<>() {
//                @Override
//                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
//                    // 进入目录前复制目录到对应位置
//                    Path saveDir = savePath.resolve(modelRootPath.relativize(dir));
//                    saveDir.toFile().mkdirs();
//                    return super.preVisitDirectory(dir, attrs);
//                }
//
//                @Override
//                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//                    // 将文件的 .ftl 替换为 .java
//                    // 将文件替换为当前的模块名
//                    String fileName = file.toFile().getName();
//                    fileName = fileName.replace(".ftl", ".java").replace(javaFileTemplateName, dto.getJavaModelName());
//                    // 生成的Java文件
//                    Path resolve = savePath.resolve(modelRootPath.relativize(file.getParent().resolve(fileName)));
//                    // 获取模板
//                    Template template = templateConf.getTemplate(templateRootPath.relativize(file).toString());
//                    try {
//                        template.process(dto, Files.newBufferedWriter(resolve));
//                    } catch (TemplateException e) {
//                        throw new MyException("根据模板生成文件异常!!", e);
//                    }
//                    return super.visitFile(file, attrs);
//                }
//            });
//        } catch (IOException e) {
//            throw new MyException("遍历模板文件出现异常!!", e);
//        }
    }

    @Override
    public void generate(GenerateDto dto, HttpServletResponse response) {

        // 1.1 参数校验
        if (dto == null) {
            throw new MyException("入参不能为空!!");
        }
        if (dto.getGroupId() == null || dto.getGroupId() < 0) {
            throw new MyException("入参【groupId】非法!!");
        }
        if (dto.getDataModel() == null) {
            throw new MyException("入参【dataModel】不应null，如无变量传入一个空对象!!");
        }
        // 2.1 校验模板组合是否存在
        TemplateGroup group = templateGroupService.getById(dto.getGroupId());
        if (group == null) {
            throw new MyException("未找到对应的模板!!");
        }
        // 2.2 获取模板组合中的模板
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("group_id", dto.getGroupId());
        List<TemplateFileInfo> fileList = templateFileInfoService.list(wrapper);
        if (fileList == null || fileList.isEmpty()) {
            throw new MyException("未找到对应的模板文件!!");
        }

        // 3. 生成文件
        Path rootPath = Paths.get(savePathStr, group.getGroupName());
        FileUtil.del(rootPath);
        try {
            for (TemplateFileInfo fileInfo : fileList) {
                Template template = templateConf.getTemplate(fileInfo.getFileUrl());
                if (template == null) {
                    throw new MyException(fileInfo.getFileUrl() + " ==> 未找到对应的模板!!");
                }
                // 后续将生成文件名
                String fileName;
                if (StringUtils.isNotBlank(fileInfo.getGenerateFileName())) {
                    // 文件名生成模板的名字
                    String fileNameTemplateName = String.valueOf(fileInfo.getPkid());
                    MyByteArrayTemplateLoader loader = (MyByteArrayTemplateLoader) templateConf.getTemplateLoader();
                    loader.putTemplate(fileNameTemplateName, fileInfo.getGenerateFileName().getBytes());
                    StringWriter writer = new StringWriter();
                    Template nameTemplate = templateConf.getTemplate(fileNameTemplateName);
                    nameTemplate.process(dto.getDataModel(), writer);
                    fileName = writer.toString();
                } else {
                    fileName = fileInfo.getTemplateFileName();
                }
                String fileDirPath = fileInfo.getFileDirPath() == null ? "/" : fileInfo.getFileDirPath();
                Path savePath = Paths.get(rootPath.toString(), fileDirPath, fileName);
                // 创建父目录
                File parentFile = savePath.getParent().toFile();
                if (!parentFile.exists()) {
                    parentFile.mkdirs();
                }
                // 生成文件
                BufferedWriter bufferedWriter = Files.newBufferedWriter(savePath);
                template.process(dto.getDataModel(), bufferedWriter);
                bufferedWriter.flush();
                bufferedWriter.close();
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new MyException("模板生成异常!!", e);
        } catch (TemplateException e) {
            log.error(e.getMessage(), e);
            throw new MyException("模板解析异常!!", e);
        }


        // 4.1 设置响应头
        String zipName = group.getGroupName() + ".zip";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(zipName));

        // 4.2 生成zip文件
        Path zipPath = Paths.get(savePathStr).resolve(zipName);
        FileUtil.del(zipPath);
        ZipUtil.zip(rootPath.toString(), zipPath.toString());
        // 4.3 下载zip文件
        try {
            IoUtil.copy(Files.newInputStream(zipPath), response.getOutputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new MyException("下载文件异常!!", e);
        }
        log.info("文件生成结束!!");
    }
}
